package com.wu.ssm.spring.aop;

import com.wu.ssm.spring.annotion.CacheClear;
import com.wu.ssm.spring.annotion.CachePut;
import com.wu.ssm.spring.aop.annotion.Aspect;
import com.wu.ssm.spring.annotion.MyService;
import com.wu.ssm.spring.aop.annotion.AspectOrder;
import com.wu.ssm.spring.cache.DefaultCacheAspect;
import com.wu.ssm.spring.core.fault.InitializationError;
import com.wu.ssm.spring.ioc.BeanHelper;
import com.wu.ssm.spring.ioc.ClassHelper;
import com.wu.ssm.spring.plugin.Plugin;
import com.wu.ssm.spring.plugin.PluginProxy;
import com.wu.ssm.spring.tx.ThransationProxy;
import org.springframework.util.CollectionUtils;

import java.lang.annotation.Annotation;
import java.util.*;

/**
 * Created by wzf on 2018/11/26/026.
 */
public final class AopHelper {

    private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(AopHelper.class);

    static {
        try {
            // 切面类 和 目标类集合 的映射
            Map<Class<?>, List<Class<?>>> proxyMap = createProxyMap();
            // 目标类 和 代理类（实例）列表 的映射
            Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
            for (Map.Entry<Class<?>, List<Proxy>> targetEntry:targetMap.entrySet()
                 ) {
                Class<?> targetClazz = targetEntry.getKey();
                List<Proxy> proxyList = targetEntry.getValue();
                // 创建代理实例
                Object proxyInstance = ProxyManager.creatProxy(targetClazz, proxyList);
                // 用代理实例覆盖目标实例，并放入 Bean 容器中
                BeanHelper.setBean(targetClazz, proxyInstance);
            }
        } catch (Exception e) {
            throw new InitializationError("初始化 AopHelper 出错！", e);
        }
    }

    /**
     * 获取 切面类 和 目标类集合 的映射
     * 所有代理类均预先创建了对象然后再交给proxyManager处理
     */
    private static Map<Class<?>, List<Class<?>>> createProxyMap(){

        Map<Class<?>, List<Class<?>>> proxyList = new LinkedHashMap<>();
        // 插件代理
        //addPluginProxy(proxyList);
        addAspectProxy(proxyList);
        addThransactionProxy(proxyList);
        addCacheProxy(proxyList);

        return proxyList;
    }

    /**
     * 返回需要创建代理的所有类列表
     */
    private static List<Class<?>> createTargetClassList(Aspect aspect){

        List<Class<?>> targrtClassList = new ArrayList<>();
        Class<? extends Annotation> annotion = aspect.value();

        if(annotion != null && !annotion.equals(Aspect.class)){
            targrtClassList.addAll(ClassHelper.getClassSetByAnnotion(annotion));
        }
        return targrtClassList;
    }



    private static void addAspectProxy(Map<Class<?>, List<Class<?>>> proxyList) {
        // 切面类 （所有继承于 AspectProxy 的类
        List<Class<?>> aspectProxyClassList = ClassHelper.getClassListBySuper(AspectProxy.class);
        // 排序切面类
        sortAspectProxyClassList(aspectProxyClassList);

        for (Class<?> proxyClass :aspectProxyClassList
        ) {
            if(proxyClass.isAnnotationPresent(Aspect.class)){
                Aspect aspect = proxyClass.getAnnotation(Aspect.class);
                List<Class<?>> targrtClassList = createTargetClassList(aspect);
                proxyList.put(proxyClass, targrtClassList);
            }
        }
    }

    private static void addThransactionProxy(Map<Class<?>, List<Class<?>>> proxyMap) {
        // 目标类
        List<Class<?>> serviceClassList = ClassHelper.getClassListByAnnotation(MyService.class);
        proxyMap.put(ThransationProxy.class, serviceClassList);
    }

    private static void addCacheProxy(Map<Class<?>, List<Class<?>>> proxyMap) {
        List<Class<?>> cacheClassList = new ArrayList<>();
        List<Class<?>> cachePutClassSet = ClassHelper.getClassListByMethodAnnotion(CachePut.class);
        List<Class<?>> cacheClearClassSet = ClassHelper.getClassListByMethodAnnotion(CacheClear.class);
        cacheClassList.addAll(cachePutClassSet);
        cacheClassList.addAll(cacheClearClassSet);
        proxyMap.put(DefaultCacheAspect.class, cacheClassList);
    }

    private static void addPluginProxy(Map<Class<?>, List<Class<?>>> proxyMap) throws Exception {
        List<Class<?>> pluginClassList = ClassHelper.getClassListBySuper(Plugin.class);

        for (Class<?> pluginClazz :pluginClassList
             ) {
            proxyMap.put(pluginClazz, pluginClassList);
        }
        if (CollectionUtils.isEmpty(pluginClassList)) {
            // 遍历所有插件代理类
            for (Class<?> pluginProxyClass : pluginClassList) {
                // 创建插件代理类实例
                PluginProxy pluginProxy = (PluginProxy) pluginProxyClass.newInstance();
                // 将插件代理类及其所对应的目标类列表放入 Proxy Map 中
                proxyMap.put(pluginProxyClass, pluginProxy.getTargetClassList());
            }
        }
    }



    /**
     * 传入 切面类 和 目标类列表 的映射
     * 返回 目标类 和 代理类（实例）列表 的映射
     */
    private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, List<Class<?>>> proxyMap) throws IllegalAccessException, InstantiationException {

        Map<Class<?>, List<Proxy>> targetMap = new HashMap<>();
        for (Map.Entry<Class<?>, List<Class<?>>> proxyEntry :proxyMap.entrySet()
        ) {
            Class<?> proxyClazz = proxyEntry.getKey();
            List<Class<?>> targetClassList = proxyEntry.getValue();
            for (Class<?> targetClazz:targetClassList
                 ) {
                Proxy proxy = (Proxy) proxyClazz.newInstance();
                if (targetMap.containsKey(targetClazz)){
                    targetMap.get(targetClazz).add(proxy);
                }else {
                    List<Proxy> proxyList = new ArrayList<>();
                    proxyList.add(proxy);
                    targetMap.put(targetClazz, proxyList);
                }
            }
        }
        return targetMap;
    }

    private static void sortAspectProxyClassList(List<Class<?>> proxyClassList){
        // 排序代理类列表
        Collections.sort(proxyClassList, new Comparator<Class<?>>() {
            @Override
            public int compare(Class<?> aspect1, Class<?> aspect2) {
                if (aspect1.isAnnotationPresent(AspectOrder.class) || aspect2.isAnnotationPresent(AspectOrder.class)) {
                    // 若有 Order 注解，则优先比较（序号的值越小越靠前）
                    if(aspect1.isAnnotationPresent(AspectOrder.class)){
                        return getOrderValue(aspect1) - getOrderValue(aspect2);
                    }else {
                        return getOrderValue(aspect2) - getOrderValue(aspect1);
                    }
                }else {
                    // 若无 Order 注解，则比较类名（按字母顺序升序排列）
                    return aspect1.hashCode() - aspect2.hashCode();
                }
            }

            private int getOrderValue(Class<?> aspect) {
                return aspect.getAnnotation(AspectOrder.class) != null ? aspect.getAnnotation(AspectOrder.class).value() : 0;
            }
        });
    }


}
